/* Copyright (C) 2007-2008  klevgert  http://code.google.com/p/db4o-netbeans/

This file is part of the db4o-netbeans module suite.

db4o-netbeans is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation and as clarified by db4objects' GPL 
interpretation policy, available at
http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
Suite 350, San Mateo, CA 94403, USA.

db4o-netbeans is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */

package com.db4o.nb.editor.nodes;

import com.db4o.ObjectContainer;
import com.db4o.nb.api.Constrain;
import com.db4o.nb.api.Db4oProvider;
import com.db4o.nb.api.Descend;
import com.db4o.nb.editor.dialogs.EnterConstraintValueDialog;
import com.db4o.nb.editor.dialogs.EnterDescendDialog;
import com.db4o.nb.util.Db4oReflectorUtil;
import com.db4o.nb.util.DialogUtil;
import com.db4o.nb.util.Updateable;
import java.awt.event.ActionEvent;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import org.openide.actions.PropertiesAction;
import org.openide.loaders.DataObject;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.util.actions.SystemAction;

/**
 * Representation of a db4o descend instance.
 * 
 * @author klevgert
 */
public class DescendNode extends AbstractNode implements Updateable {
  
  private static final String ICON_PATH = "com/db4o/nb/editor/resources/descend2.gif";

  private Descend descend;
    
  /**
   * Creates a new instance of DescendNode
   */
  public DescendNode(Descend descend) {
//    super( (descendElement.getChildNodes().getLength()>0)? 
//            new Db4oDescendNodeChildren(descendElement) : Children.LEAF);
    super( new DescendNodeChildren(descend) );
    
    this.descend = descend;
    
    this.setDisplayName("descend: " + descend.getValue());
    this.setIconBaseWithExtension(ICON_PATH);
    
  }
  
  /**
   * Gets the action that could be performed on the node.
   * @param b   flag indicating if the menu is a popup 
   * @return Array of actions to execute on the node
   */
  public Action[] getActions(boolean b) {

    return new Action[] { 
      new AddDescendAction(),
      new AddConstrainAction(),
      null,
//      new DeleteAction()
      SystemAction.get(PropertiesAction.class)      
    };
  }  
  
  public void reloadChildren() {
    this.setChildren(new DescendNodeChildren(this.descend));
  }

  public void update() {
    this.reloadChildren();
  }

  
  // <editor-fold defaultstate="collapsed" desc=" Actions ">                          

   /**
   * Adds a descend node to the query
   */
  private class AddDescendAction extends AbstractAction {
    
    public AddDescendAction() {
      this.putValue(NAME,"Add Descend...");
    }
    
    public void actionPerformed(ActionEvent e) {
      
      Node node = DescendNode.this;
      while( !(node instanceof QueryNode) ) {
        node = node.getParentNode();
      }
      QueryNode queryNode = (QueryNode)node;
      Db4oDataNode db4oNode = (Db4oDataNode)queryNode.getParentNode().getParentNode();
      DataObject dataObj = db4oNode.getDataObject();
      Db4oProvider provider = (Db4oProvider)db4oNode.getLookup().lookup(Db4oProvider.class);

      String type = descend.getType();
      List typeNames = Db4oReflectorUtil.getDeclaredFields(type, provider.getDatabase().getObjectContainer());
        
      EnterDescendDialog dlg = new EnterDescendDialog(new javax.swing.JFrame(), true);
      dlg.setNames(typeNames);
      dlg.setVisible(true);
      if( dlg.getReturnStatus() == EnterDescendDialog.RET_CANCEL ) {
        return;
      }

      String name = dlg.getSelectedName();
      if( name == null ) {
        return;
      }
      
      Descend newDescend = provider.createDescend(type,name);
     
      descend.add(newDescend);
      dataObj.setModified(true);

      DescendNode newDb4oNode = new DescendNode(newDescend);
      DescendNode.this.getChildren().add(new Node[] {newDb4oNode});
    }
  }
  
   /**
   * Adds a descend node to the query
   */
  private class AddConstrainAction extends AbstractAction {
    
    public AddConstrainAction() {
      String displayName = NbBundle.getMessage(this.getClass(), "AddConstrain");
      this.putValue(NAME,displayName);
    }
    
    public void actionPerformed(ActionEvent e) {
            
      Node node = DescendNode.this;
      while( !(node instanceof QueryNode) ) {
        node = node.getParentNode();
      }
      QueryNode queryNode = (QueryNode)node;
      Db4oDataNode db4oNode = (Db4oDataNode)queryNode.getParentNode().getParentNode();
      DataObject dataObj = db4oNode.getDataObject();
      Db4oProvider provider = (Db4oProvider)db4oNode.getLookup().lookup(Db4oProvider.class);
      
      EnterConstraintValueDialog dlg = new EnterConstraintValueDialog(new javax.swing.JFrame(), true);
      dlg.setVisible(true);
      if( dlg.getReturnStatus() == EnterConstraintValueDialog.RET_CANCEL ) {
        return;
      }

      String value = dlg.getValue();
      if( value == null ) {
        return;
      }
      
      String clstype = DescendNode.this.descend.getType();
      String name = DescendNode.this.descend.getValue();
      ObjectContainer oc = provider.getDatabase().getObjectContainer();
      String fldtype = Db4oReflectorUtil.getDeclaredFieldType(name,clstype,oc);
      
      Constrain newConstrain = provider.createConstrain(fldtype,value);
      
      descend.add(newConstrain);
      dataObj.setModified(true);

      DescendNode.this.reloadChildren();
    }
    
    private String determineType() {
      return "java.lang.String";
    }
  }
  
  /**
   * Deletes this query node.
   */
  private class DeleteAction extends AbstractAction {
    
    public DeleteAction() {
      String name = NbBundle.getMessage(this.getClass(), "Delete");
      this.putValue(NAME, name);
    }
    
    public void actionPerformed(ActionEvent e) {
      
      String confirmmsg = NbBundle.getMessage(this.getClass(), "ConfirmDeleteDescend");
      if (DialogUtil.confirmYesNo(confirmmsg).equals(DialogUtil.YES)) {

          // Remove from xml element
         
//          org.w3c.dom.Element parentElem = (org.w3c.dom.Element)descendElement.getParentNode();
//          parentElem.removeChild(descendElement);

          // Save it
          Node node = DescendNode.this;
          DataObject dataObj = (DataObject)node.getLookup().lookup(DataObject.class);
          dataObj.setModified(true);

          // Remove from node tree
          DescendNode.this.getParentNode().getChildren().remove(new Node[] {DescendNode.this});
          ((Updateable)DescendNode.this.getParentNode()).update();
       }
    }
    
    
  }
  
  // </editor-fold>

  // <editor-fold defaultstate="collapsed" desc=" Children ">                          
  
  public static class DescendNodeChildren  extends Children.Keys {

    private Descend descend;

    /** Creates a new instance of Db4oQueryNodeChildren */
    public DescendNodeChildren(Descend descend) {
      this.descend = descend;
    }

    protected Node[] createNodes(Object object) {

      AbstractNode result = null;
      if( object instanceof Descend ) {
        result = new DescendNode( (Descend)object );
      } else {
        result = new ValueConstrainNode( (Constrain)object );
      }
      return new Node[] {result};

    }

    protected void addNotify() {
      setKeys( this.descend.getChildren().toArray() );
    }

  }
  
  // </editor-fold>                          

}
